<?php abstract class Out implements iReconfigurable {
	protected static $ExistingLevels = array ('EMERG', 'ALERT', 'CRIT', 'ERR', 'WARNING', 'NOTICE', 'INFO', 'DEBUG');
	protected static $Levels = array ();
	public static function Stdout ($Message) {echo ("$Message\n");}
	public static function CheckLevel ($Level) {
		$Level = strtoupper ($Level);
		return (in_array ($Level, self::$ExistingLevels)) ? $Level : self::$ExistingLevels;
	}
	public static function Reconfigure (array $Config) {
		if (array_key_exists ('level', $Config)) {
			self::I (Msg::ConfigGot, 'level', $Level = $Config ['level']);
			if ($Level !== (string) (int) $Level) { // string, not integer
				if (is_array ($ULevel = self::CheckLevel ($Level))) {
					self::W (Msg::UnknownSyslogLvl, $Level, implode (', ', $ULevel));
					$Level = -1;
				} else $Level = constant ("LOG_$ULevel");
			}
			($Level >= 0) and self::I (Msg::ConfigApplied, 'level', self::$Levels ['config'] = $Level);
		}
		$Facility = 'LOG_DAEMON';
		if (array_key_exists ('facility', $Config)) {
			self::I (Msg::ConfigGot, 'facility', $Config ['facility']);
			if (defined ($TF = 'LOG_'.strtoupper ($Config ['facility']))) {
				self::I (Msg::ConfigApplied, 'facility', $Facility = $TF);
			} else self::W (Msg::UnknownFacility, $TF, $Facility);
		}
		openlog ('overwatchd', LOG_PID, constant ($Facility));
	}
	protected static function LogMessage ($Level, $Message) {
		// determine line's level
		switch ($Level) {
			case 'debug':   $Prio = LOG_DEBUG; break;
			case 'warning': $Prio = LOG_WARNING; break;
			case 'fatal':   $Prio = LOG_ERR; break;
			default:        $Prio = LOG_INFO;
		}
		// determine current log level
		if (! array_key_exists ('options', self::$Levels)) {
			self::$Levels ['default'] = self::$Levels ['options'] = Options::LogLevel ();
			Options::LLSet () or self::$Levels ['options'] = NULL;
		}
		if (NULL === self::$Levels ['options']) {
			$CurLevel = (array_key_exists ('config', self::$Levels)) ? self::$Levels ['config'] : self::$Levels ['default'];
		} else $CurLevel = self::$Levels ['options'];
		// do or do not write the message
		if ($Prio > $CurLevel) return (NULL);
		is_array ($Message) and $Message = call_user_func_array ('sprintf', $Message);
		// extract caller if one exists
		$Caller = '';
		if ((count ($Trace = debug_backtrace ()) > 2)) {
			$Caller = $Trace [2];
			switch ($Caller ['type']) {
				case '::': case '->': $Caller = $Caller ['class'].$Caller ['type'].$Caller ['function']; break;
				default: $Caller = $Caller ['function']; break;
			}
		}
		strlen ($Caller) and $Message = "($Caller) $Message";
		// is it still on? okay, finally let's do something
		if (Daemon::Detached ()) {
			syslog ($Prio, $Message);
		} else fputs (STDERR, "$Level: $Message\n");
	}
	public static function D () {
		$Args = func_get_args ();
		self::LogMessage ('debug', $Args);
	}
	public static function I () {
		$Args = func_get_args ();
		self::LogMessage ('info', $Args);
	}
	public static function W () {
		$Args = func_get_args ();
		self::LogMessage ('warning', $Args);
	}
	public static function F () {
		$Args = func_get_args ();
		self::LogMessage ('fatal', $Args);
		Daemon::Down ();
	}
} ?>